package com.gbase8c.dmt.migration.job;

import com.gbase8c.dmt.common.util.Exceptions;
import com.gbase8c.dmt.migration.MoLogger;
import com.gbase8c.dmt.model.enums.MigrationObjectType;
import com.gbase8c.dmt.model.migration.dto.MigrationObject;
import com.gbase8c.dmt.model.migration.record.JobThreadRecord;
import com.gbase8c.dmt.model.enums.Status;
import com.gbase8c.dmt.model.migration.record.Mo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.lang3.time.DateFormatUtils;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.List;

@Slf4j
public class SqlJobThread extends AbstractJobThread{

    public SqlJobThread(MigrationObjectType type, MigrationObject dbObject, DataSource tarDataSource, MoLogger moLogger) {
        super(type, dbObject, tarDataSource, moLogger);
    }

    @Override
    public JobThreadRecord call() throws Exception {
        Mo mo = Mo.builder()
                .name((MigrationObjectType.TABLESPACE.equals(type)
                        || MigrationObjectType.SCHEMA.equals(type))
                        ? dbObject.getName() : dbObject.getSchema() + "." + dbObject.getName())
                .status(Status.InProgress.name())
                .build();
        moLogger.log(mo);
        long beginTime = System.currentTimeMillis();
        JobThreadRecord jobThreadRecord = new JobThreadRecord();
        List<String> contents = dbObject.getContents();
        QueryRunner queryRunner = new QueryRunner(this.tarDataSource);
        jobThreadRecord.setSchemaName(dbObject.getSchema());
        try {
            //todo:添加convert转换成功与否判断
            if (dbObject.getConvertible()){
                for (String sql : contents){
                    int execute = queryRunner.execute(sql);
                    long endTime = System.currentTimeMillis();

                    log.info(   "\n type                 : {} " +
                                "\n sql                  : {} " +
                                "\n execute result       : {} " +
                                "\n spend total time     : {}ms " +
                                "\n start time           : {}" +
                                "\n end time             : {}"
                            , dbObject.getMigrationObjectType()
                            ,sql.replaceAll(System.getProperty("line.separator"),"")
                            ,execute == 0 ? "success" : "failed"
                            ,(endTime - beginTime)
                            ,DateFormatUtils.format(beginTime,"yyyy-MM-dd HH:mm:ss.SSS")
                            ,DateFormatUtils.format(endTime,"yyyy-MM-dd HH:mm:ss.SSS"));
                }
                jobThreadRecord.setFlag(true);
                dbObject.setStatus(Status.Finished);
                mo.setStatus(Status.Finished.name());
            } else {
                dbObject.setMsg(dbObject.getConvertMsg());
                jobThreadRecord.setFlag(false);
                dbObject.setStatus(Status.Failure);
                jobThreadRecord.setErrorLog(dbObject.getConvertMsg());
                mo.setStatus(Status.Failure.name());
                mo.setMsg(dbObject.getConvertMsg());
            }
        } catch (SQLException exception) {
            String sqlState = exception.getSQLState();
            // 42P06 OpenGauss数据库标准错误码：模式重复，由于设计原因，重复的模式不显示报错。
            if ("42P06".equals(sqlState)){
                jobThreadRecord.setFlag(true);
                dbObject.setStatus(Status.Finished);
                mo.setStatus(Status.Finished.name());
            } else {
                dbObject.setMsg(exception.getMessage());
                dbObject.setStatus(Status.Failure);
                jobThreadRecord.setFlag(false);
                jobThreadRecord.setErrorLog(Exceptions.getStackTraceAsString(exception));
                mo.setStatus(Status.Failure.name());
                mo.setMsg(exception.getMessage());
            }
            log.error("execute sql job error error,cause: {}", exception.getMessage(),exception);
        }
        jobThreadRecord.setDbObject(dbObject);
        moLogger.log(mo);
        return jobThreadRecord;
    }
}
